use std::fmt::{Debug, Display};

use std::fs::remove_dir_all;

use chrono::{Datelike, Local, Timelike};

use regex::Regex;
use serde::{de::DeserializeOwned, Deserialize, Serialize};

use crate::error::WResult;

use crate::app::get_wtask_data_dir;

use crate::cmd::file_name_remove_space;





pub trait TimerAppTrait
where
    Self: Sized + Debug + Clone + Send,
    Self::Key: Sized + Debug + Clone + DeserializeOwned + Send,
{
    type Key;
    fn get_note(&self) -> WResult<&str>;
    fn get_cmd_and_args(self) -> (String, Vec<String>);
    fn run(self) -> impl Future<Output = WResult<Self::Key>> + Send;
    fn save(self, name: &str, log: &[Self::Key]) -> impl Future<Output = WResult<()>> + Send;
    fn load(f: &Self::Key) -> impl Future<Output = WResult<(Self, Vec<Self::Key>)>> + Send;
    fn get_all_timer() -> impl Future<Output = WResult<Vec<Self::Key>>> + Send;
    fn timer_str(timer: &Self::Key) -> &str;
}


fn timer_single_f(l0: &str, v: &str, l1: &str) -> String {
    let t = if v.starts_with("_") {
        "每"
    } else {
        "第"
    };
    format!("{}{}{}{}", l0, t, v.trim_start_matches("_"), l1)
}

pub fn parse_timer(data: &str) -> Vec<&str> {
    let re = Regex::new(r"(_?\d+)").unwrap();
    
    data.splitn(6, " ")
        .filter(| v | {
            re.is_match(v)
        }).collect::<Vec<_>>()
}


#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimerBasic {
    pub create_time: String,
    pub year: String,
    pub month: String,
    pub day: String,
    pub hour: String,
    pub min: String,
    pub week: String,
    pub note: String,
}

impl TimerBasic {
    pub fn convert_to_display(self) -> Self {
        let t = self.create_time.chars().collect::<Vec<_>>();
        let t = format!(
            "{}{}{}{}-{}{}-{}{} {}{}:{}{}:{}{}",
            t[0],
            t[1],
            t[2],
            t[3],
            t[4],
            t[5],
            t[6],
            t[7],
            t[8],
            t[9],
            t[10],
            t[11],
            t[12],
            t[13],
        );
        Self {
            create_time: t,
            year: timer_single_f("", &self.year, "年"),
            month: timer_single_f("", &self.month, "月"),
            day: timer_single_f("", &self.day, "日"),
            hour: timer_single_f("", &self.hour, "小时"),
            min: timer_single_f("", &self.min, "分钟"),
            week: timer_single_f("星期", &self.week, "天"),
            note: self.note
        }
    }
}



#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimerRunFmt<R> {
    pub name: String,
    pub basic: TimerBasic,
    pub app_cmd: String,
    pub app_args: Vec<String>,
    pub log: Vec<R>,
}


#[derive(Debug, Clone)]
pub struct TimerRunConfig<T: TimerAppTrait> {
    pub app: T,
    // dir_result(archv)
    pub log: Vec<T::Key>,
}


#[derive(Debug, Clone)]
pub struct TimerRun<T: TimerAppTrait> {
    pub basic: TimerBasic,
    config: TimerRunConfig<T>,
    pub name: String,
}

impl<T: TimerAppTrait> TimerRun<T> {
    /// 从字符串生成该timer配置
    pub fn new(timer: &str, app: T) -> WResult<Self> {
        let mut timer = parse_timer(timer);
        timer.reverse();
        // 定时任务不等待，仅提交任务
        let note = app.get_note()?;
        // log::info!("Timer: {timer:?}");
        let mut res = Self {
            basic: TimerBasic {
                min: timer.pop().unwrap_or("_1").to_string(),
                hour: timer.pop().unwrap_or("_1").to_string(),
                day: timer.pop().unwrap_or("_1").to_string(),
                week: timer.pop().unwrap_or("_1").to_string(),
                month: timer.pop().unwrap_or("_1").to_string(),
                year: timer.pop().unwrap_or("_1").to_string(),
                create_time: Local::now().format("%Y%m%d%H%M%S").to_string(),
                note: file_name_remove_space(note),
            },
            config: TimerRunConfig {
                app,
                log: Vec::new()
            },
            name: "".to_string()
        };
        res.name = res.get_name();
        Ok(res)
    }

    pub fn logs(&self) -> &[T::Key] {
        &self.config.log
    }

    
    pub fn extract_config(self) -> TimerRunConfig<T> {
        self.config
    }
    
    /// 保存配置到文件
    pub async fn save(self) -> WResult<()> {
        self.config.app.save(&self.name, &self.config.log).await?;
        Ok(())
    }

    /// 从文件加载配置
    pub async fn load(f: &T::Key) -> WResult<Self> {
        let name = T::timer_str(f);
        let meta_temp = Self::parse_timer_basic(name);
        let config_temp = T::load(f).await?;
        Ok(Self {
            basic: meta_temp,
            config: TimerRunConfig { app: config_temp.0, log: config_temp.1 },
            name: name.to_string()
        })
    }

    fn get_name(&self) -> String {
        format!(
            "{}.{}.{}.{}.{}.{}.{}.{}",
            self.basic.create_time,
            self.basic.year,
            self.basic.month,
            self.basic.day,
            self.basic.hour,
            self.basic.min,
            self.basic.week,
            self.basic.note,
        )
    }

    pub async fn del(n: &str) -> WResult<()> {
        let p_timer = get_wtask_data_dir("timer", false)?.join(n);
        if p_timer.exists() && p_timer.is_dir() {
            log::info!("Del Timer: {p_timer:?}");
            remove_dir_all(&p_timer)?;
        }
        Ok(())
    }

    fn parse_timer_str(f: &str) -> Vec<&str> {
        f.splitn(8, ".").collect::<Vec<_>>()
    }

    pub fn parse_timer_basic(f: &str) -> TimerBasic {
        let meta_temp = Self::parse_timer_str(f);
        TimerBasic {
            create_time: meta_temp[0].to_string(),
            year: meta_temp[1].to_string(),
            month: meta_temp[2].to_string(),
            day: meta_temp[3].to_string(),
            hour: meta_temp[4].to_string(),
            min: meta_temp[5].to_string(),
            week: meta_temp[6].to_string(),
            note: meta_temp[7].to_string(),
        }
    }

    fn match_time(now: u32, data: &str) -> bool {
        let rule = if let Some(data_now) = data.strip_prefix("_") {
            data_now.parse::<u32>()
        } else {
            data.parse::<u32>()
        };
        if rule.is_err() {
            return false;
        }

        let rule = rule.unwrap();

        if data.starts_with("_") {
            now.is_multiple_of(rule)
        } else {
            now == rule
        }
    }
    
    pub async fn run(mut self) {
        log::debug!("Timer running: {:?} ...", self.name);
        match self.config.app.clone().run().await {
            Ok(dir_result_temp) => {
                self.config.log.push(dir_result_temp);
            },
            Err(e) => {
                log::error!("Timer run error: {:?} {}", self, e);
            }
        }
        let _ = self.config.app.save(&self.name, &self.config.log).await;
    }

    /// 运行文件夹内的所有配置任务，如果需要运行的话
    /// 运行的时候扫描temp文件夹，删除过久文件
    pub async fn run_all() -> WResult<()> {

        let time_now = Local::now();
        let time_now_all = [
            time_now.year() as u32,
            time_now.month(),
            time_now.day(),
            time_now.hour(),
            time_now.minute(),
            time_now.weekday().num_days_from_monday() + 1,
        ];

        for f_timer_single in T::get_all_timer().await? {
            let time_str = T::timer_str(&f_timer_single);
            let t = Self::parse_timer_str(time_str);

            let need_run = t.into_iter().skip(1).zip(time_now_all).all(| (v, i) |{
                Self::match_time(i, v)
            });
            
            log::debug!("Timer: {need_run} {f_timer_single:?}");

            if !need_run {
                continue;
            }

            let timer_temp = Self::load(&f_timer_single).await;
            if let Ok(timer_single) = timer_temp {
                timer_single.run().await;
            } else {
                log::error!("Timer parse error: {:?} {:?}", f_timer_single, timer_temp.err());
            }

        }
        Ok(())
    }


    pub fn to_fmt(self) -> TimerRunFmt<T::Key> {
        let (app_cmd_temp, app_args_temp) = self.config.app.get_cmd_and_args();
        TimerRunFmt {
            name: self.name,
            basic: self.basic.convert_to_display(),
            app_cmd: app_cmd_temp,
            app_args: app_args_temp,
            log: self.config.log,
        }
    }
}





#[derive(Debug, Serialize, Deserialize)]
pub struct TimerList<R> {
    pub data: Vec<TimerRunFmt<R>>
}

impl<R> Display for TimerList<R> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let lines = self.data.iter().map(| v |{
            format!("{}\t{}\t{}\t{}/{}/{}/{}/{}/{}", v.basic.create_time, v.log.len(), v.name, v.basic.year, v.basic.month, v.basic.day, v.basic.week, v.basic.hour, v.basic.min)
        }).collect::<Vec<_>>().join("\n");
        write!(f, "Timer num: {}\nCreateTime\t\tTimes\tName\t\t\t\t\t\t\tTimer\n{}", self.data.len(), lines)
    }
}


